﻿/// ****************************************************************************
/// Author:	        Robin Zhu
/// Create Date:	2013-12-12
/// Purpose: 		有缓存的带Key记录的集合类定义文件
/// ****************************************************************************
/// Modify By		Date			Remark
/// Robin           2014-6-11       修正清除Cache后，索引器仍然读到Cache对象的问题
/// ****************************************************************************

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace RB.Domain.RelationalMapping
{
    public abstract class CachedKeyedRecordSet<TItem, TKey> : KeyedRecordSet<TItem, TKey>
        where TItem : class
    {
        private static object _locker = new object();
        private static bool _cacheLoaded = false;
        private static Dictionary<TKey, TItem> _cache = new Dictionary<TKey, TItem>();

        protected abstract TItem GetValue(TKey key);
        protected abstract void SetValue(TKey key, TItem value);

        public override TItem this[TKey key]
        {
            get
            {
                TItem value;
                if (!_cacheLoaded || !_cache.TryGetValue(key, out value))
                {
                    value = GetValue(key);
                }
                return value;
            }
            set
            {
                _cache[key] = value;
                SetValue(key, value);
            }
        }

        protected abstract TKey GetKey(TItem item);

        public override bool Contains(TItem item)
        {
            bool result = false;
            TKey key = GetKey(item);
            if (_cacheLoaded)
                result = _cache.ContainsKey(key);
            else
                result = GetValue(key) != null;
            return result;
        }

        protected abstract bool RemoveByKey(TKey key, DataAccess.Executor exec);

        public override bool Remove(TItem item, DataAccess.Executor exec)
        {
            TKey key = GetKey(item);
            _cache.Remove(key);
            return RemoveByKey(key, exec);
        }

        public override void Add(TItem item, DataAccess.Executor exec)
        {
            TKey key = GetKey(item);
            _cache[key] = item;
            base.Add(item, exec);
        }

        public override bool Any(System.Linq.Expressions.Expression<Func<TItem, bool>> predicate)
        {
            bool result = false;
            if (_cacheLoaded)
                result = _cache.Values.AsQueryable().Any(predicate);
            else
                result = base.Any(predicate);
            return result;
        }

        public override int RemoveAll(System.Linq.Expressions.Expression<Func<TItem, bool>> match, DataAccess.Executor exec)
        {
            ClearCache();
            return base.RemoveAll(match, exec);
        }

        public override int Update<TField>(System.Linq.Expressions.Expression<Func<TItem, TField>> fields, System.Linq.Expressions.Expression<Func<TItem, bool>> match, DataAccess.Executor exec)
        {
            ClearCache();
            return base.Update<TField>(fields, match, exec);
        }

        public override IQueryable<TItem> Where(System.Linq.Expressions.Expression<Func<TItem, bool>> predicate)
        {
            LoadCache();
            return _cache.Values.AsQueryable().Where(predicate);
        }

        public override TItem First()
        {
            if (_cacheLoaded)
            {
                return _cache.Values.First();
            }
            return base.First();
        }

        public override TItem First(System.Linq.Expressions.Expression<Func<TItem, bool>> predicate)
        {
            if (_cacheLoaded)
            {
                return _cache.Values.AsQueryable().First(predicate);
            }
            return base.First(predicate);
        }

        public override TItem FirstOrDefault()
        {
            if (_cacheLoaded)
            {
                return _cache.Values.FirstOrDefault();
            }
            return base.FirstOrDefault();
        }

        public override TItem FirstOrDefault(System.Linq.Expressions.Expression<Func<TItem, bool>> predicate)
        {
            if (_cacheLoaded)
            {
                return _cache.Values.AsQueryable().FirstOrDefault(predicate);
            }
            return base.FirstOrDefault(predicate);
        }

        public override TItem Single(System.Linq.Expressions.Expression<Func<TItem, bool>> predicate)
        {
            if (_cacheLoaded)
            {
                return _cache.Values.AsQueryable().Single(predicate);
            }
            return base.Single(predicate);
        }

        public override TItem SingleOrDefault(System.Linq.Expressions.Expression<Func<TItem, bool>> predicate)
        {
            if (_cacheLoaded)
            {
                return _cache.Values.AsQueryable().SingleOrDefault(predicate);
            }
            return base.SingleOrDefault(predicate);
        }

        public override List<TItem> ToList()
        {
            LoadCache();
            return _cache.Values.ToList();
        }

        private void LoadCache()
        {
            lock (_locker)
            {
                if (!_cacheLoaded)
                {
                    _cache = base.ToList().ToDictionary(p => GetKey(p));
                    _cacheLoaded = true;
                }
            }
        }

        private void ClearCache()
        {
            lock (_locker)
            {
                _cacheLoaded = false;
            }
        }
    }
}
